package com.gk.panda.apis.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gk.panda.apis.Vo.exports.ExportBounderyVO;
import com.gk.panda.apis.dto.BoundaryDto;
import com.gk.panda.apis.dto.BoundarySaveDto;
import com.gk.panda.apis.dto.imports.ImportBounderyDTO;
import com.gk.panda.apis.mapper.BoundaryMapper;
import com.gk.panda.apis.service.BoundaryService;
import com.gk.panda.apis.service.OrgService;
import com.gk.panda.apis.util.ListCopyUtils;
import com.gk.panda.apis.util.excel.ExcelUtils;
import com.gk.panda.commons.exception.ServerException;
import com.gk.panda.commons.util.UserUtil;
import com.gk.panda.pojo.Boundary;
import com.gk.panda.pojo.Org;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


@Service
public class BoundaryServiceImpl extends ServiceImpl<BoundaryMapper, Boundary> implements BoundaryService {

    /**
     * 文件地址
     */
    private static final String TEMPLATE_FILE_NAME = "勘界导入模板.xlsx";
    /**
     * 文件模板后缀
     */
    private static final String FILE_SUFFIX = ".xlsx";

    @Autowired
    private OrgService orgService;

    /**
     * 分页查询勘界信息
     * @param dto
     * @return
     */
    @Override
    public Page<Boundary> getBoundary(BoundaryDto dto) {
        Page<Boundary> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        QueryWrapper<Boundary> wrapper = new QueryWrapper<>();
        if (dto.getSearchParam() != null && !dto.getSearchParam().equals("")) {
            wrapper.and(queryWrapper -> {
                queryWrapper.like("num", dto.getSearchParam())
                        .or().like("remark", dto.getSearchParam())
                        .or().like("type",dto.getSearchParam());
            });
        }
        wrapper.in(dto.getOrgIds() != null, "org_id", dto.getOrgIds());
        wrapper.gt(dto.getStartTime() != null, "create_time", dto.getStartTime());
        wrapper.lt(dto.getEndTime() != null, "create_time", dto.getEndTime());
        wrapper.in(dto.getType() != null, "type", dto.getType());
        wrapper.orderByDesc("create_time");
        return this.baseMapper.selectPage(page, wrapper);
    }

    /**
     * 添加勘界信息
     * @param dto
     * @return
     */
    @Override
    public boolean addBoundary(BoundarySaveDto dto) {
        Boundary boundary = new Boundary();
        boundary.setOrgId(dto.getOrgId());
        boundary.setType(dto.getType());
        boundary.setCreateTime(dto.getCreateTime());
        boundary.setNum(dto.getNum());
        boundary.setElevation(dto.getElevation());
        boundary.setLot(dto.getLot());
        boundary.setLat(dto.getLat());
        boundary.setRemark(dto.getRemark());
        boundary.setCreator(UserUtil.getCurrentUser());
        return this.save(boundary);
    }

    /**
     * 勘界导入模板下载
     *
     * @param response P
     */
    @Override
    public void downloadTemplate(HttpServletResponse response) {
        XSSFWorkbook workbook = getWorkbook();
        XSSFSheet sheet = workbook.getSheetAt(0);
        // 所属机构
        List<Org> orgs = orgService.list();
        String[] names = orgs.stream().map(Org::getName).toArray(String[]::new);
        ExcelUtils.setDropDownBox(sheet, 1, 0, 65535, 0, names, workbook, "机构");

        // 类型
        String[] staffStatus = {"界碑", "界桩", "区桩", "界牌", "指向标识", "禁止标识", "提示标识", "警示标识"};
        ExcelUtils.setDropDownBox(1, 65535, 4, 4, sheet, staffStatus);

        // 生成文件
        String downloadFileName = "勘界信息" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }

    /**
     * 导入勘界信息
     *
     * @param file P
     * @return R
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importBoundary(MultipartFile file) {
        // 加载Excel文件
        InputStream inputStream = null;
        // 数据解析(mapping映射), pojoClass映射
        List<ImportBounderyDTO> resultList = null;
        try {
            inputStream = file.getInputStream();
            // 选择Sheet,params默认选择第一个sheet
            ImportParams params = new ImportParams();
            // 读取第几个sheet
            params.setStartSheetIndex(0);
            // 每次读取几个sheet
            params.setSheetNum(1);
            // titleRows表示的是表格标题行数，如果没有就是0，如果有一个标题就是1，如果是两个标题就2
            params.setTitleRows(0);
            // 头部占几行
            params.setHeadRows(1);
            // 校验导入字段
            // params.setImportFields(new String[]{"编号"});
            resultList = ExcelImportUtil.importExcel(inputStream, ImportBounderyDTO.class, params);
        } catch (Exception e) {
            e.printStackTrace();
            return "failed";
        }
        if (CollectionUtils.isEmpty(resultList)) {
            return "导入数据为空，请检查填入数据！";
        }
        // 通过机构名称获取机构id
        List<String> names = resultList.stream().map(ImportBounderyDTO::getOrgName).collect(Collectors.toList());
        List<Org> orgList = orgService.list(Wrappers.<Org>lambdaQuery().in(Org::getName, names));
        String username = UserUtil.getCurrentUser();
        resultList.forEach(k -> {
            for (Org v : orgList) {
                if (v.getName().equals(k.getOrgName())) {
                    k.setOrgId(v.getId());
                }
            }
            k.setCreator(username);
        });
        List<Boundary> boundaries = ListCopyUtils.copyListProperties(resultList, Boundary::new);
        //校验导入部分是否有重复编号
        List<String> nums = boundaries.stream().map(Boundary::getNum).collect(Collectors.toList());
        Set<String> set = new HashSet<>();
        List<String> collect = nums.stream().filter(x -> !set.add(x)).collect(Collectors.toList());
        if (collect.size() > 0) {
            return "表格有重复编号：" + StringUtils.join(collect,",");
        }
        //校验导入部分和数据库是否有重复编号
        QueryWrapper<Boundary> wrapper = new QueryWrapper<>();
        wrapper.in("num",nums);
        List<Boundary> list = list(wrapper);
        if (list != null && list.size() > 0) {
            return "与已有编号重复：" + StringUtils.join(list.stream().map(Boundary::getNum).collect(Collectors.toList()),",");
        }
        //导入
        saveBatch(boundaries);
        return "success";
    }

    /**
     * 导出勘界信息
     *
     * @param response P
     */
    @Override
    public void exportBoundary(HttpServletResponse response) {
        // 查询全部数据
        List<Boundary> boundaries = list(Wrappers.<Boundary>lambdaQuery().orderByDesc(Boundary::getCreateTime));
        if (CollectionUtils.isEmpty(boundaries)) {
            throw new ServerException("暂无数据导出！");
        }
        // 机构名称查询
        List<Integer> orgIds = boundaries.stream().map(Boundary::getOrgId).collect(Collectors.toList());
        List<Org> orgs = orgService.listByIds(orgIds);
        List<ExportBounderyVO> vos = ListCopyUtils.copyListProperties(boundaries, ExportBounderyVO::new);
        vos.forEach(k -> {
            for (Org v: orgs) {
                if (v.getId().equals(k.getOrgId())) {
                    k.setOrgName(v.getName());
                }
            }
        });
        // 导出
        ExportParams params = new ExportParams();
        // params.setTitle("勘界信息列表");
        params.setSheetName("勘界信息");
        params.setHeight((short) 15);
        Workbook workbook = ExcelExportUtil.exportBigExcel(params, ExportBounderyVO.class, vos);
        ExcelExportUtil.closeExportBigExcel();
        // 生成文件
        String downloadFileName = "勘界信息导出" + FILE_SUFFIX;
        ExcelUtils.download(downloadFileName, workbook, response);
    }


    /**
     * 获取workbook
     *
     * @return XSSFWorkbook
     */
    private XSSFWorkbook getWorkbook() {
        InputStream inputStream;
        XSSFWorkbook workbook;
        try {
            ClassPathResource classPathResource = new ClassPathResource("excels/" + TEMPLATE_FILE_NAME);
            inputStream = classPathResource.getInputStream();
            workbook = new XSSFWorkbook(inputStream);
        } catch (IOException e) {
            throw new ServerException("勘界导入模板获取异常！");
        }
        return workbook;
    }
}
